home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / p_mat.exe / PMAT.DOC < prev    next >
Encoding:
Text File  |  1993-01-24  |  48.1 KB  |  1,311 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.           P-Mat v1.2
  20.           An Turbo Pascal program for Recursive Matrix Algebra
  21.  
  22.           Mark Von Tress, Ph.D.
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.           PO Box 171173
  47.           Arlington TX 76003
  48.  
  49.  
  50.           Compuserve User ID : 71530,1170
  51.  
  52.  
  53.           Date: January 30, 1993
  54.  
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61.  
  62.  
  63.           You are responsible for what you do with the
  64.           code. Here is a formal disclaimer:
  65.  
  66.  
  67.           DISCLAIMER: THIS PROGRAM IS PROVIDED AS IS, WITHOUT ANY
  68.           WARRANTY, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  69.           TO FITNESS FOR A PARTICULAR PURPOSE. THE AUTHOR DISCLAIMS
  70.           ALL LIABILITY FOR DIRECT OR CONSEQUENTIAL DAMAGES RESULTING
  71.           FROM USE OF THIS PROGRAM.
  72.  
  73.  
  74.           Copyright (c) Mark Von Tress 1993
  75.  
  76.  
  77.  
  78.  
  79.  
  80.  
  81.  
  82.           Mat-P 3
  83.  
  84.  
  85.                                   Table of Contents
  86.  
  87.  
  88.           I. INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . .   4
  89.  
  90.           II. FINANCIAL CONDITIONS OF USE . . . . . . . . . . . . . . .   4
  91.  
  92.           III. BASIC ALGORITHMS . . . . . . . . . . . . . . . . . . . .   5
  93.                A. Structures and Allocation . . . . . . . . . . . . . .   5
  94.                B. The global stack: dispatch  . . . . . . . . . . . . .   7
  95.                C. Recursion . . . . . . . . . . . . . . . . . . . . . .   7
  96.                D. Matrix Assignment . . . . . . . . . . . . . . . . . .   8
  97.                E. Parameter Passing . . . . . . . . . . . . . . . . . .   9
  98.  
  99.           IV. FUNCTIONS . . . . . . . . . . . . . . . . . . . . . . . .  10
  100.                A. Error Handling  . . . . . . . . . . . . . . . . . . .  10
  101.                B. Array Allocation or Deallocation  . . . . . . . . . .  11
  102.                C. Stack Control . . . . . . . . . . . . . . . . . . . .  11
  103.                D. Matrix Allocation, Deallocation and Copy  . . . . . .  13
  104.                E. Display Functions . . . . . . . . . . . . . . . . . .  14
  105.                F. Matrix IO . . . . . . . . . . . . . . . . . . . . . .  15
  106.                G. Binary Matrix Functions . . . . . . . . . . . . . . .  16
  107.                H. Unary Matrix Functions  . . . . . . . . . . . . . . .  17
  108.                I. Patterned Matrices  . . . . . . . . . . . . . . . . .  19
  109.                J. Mathematical Functions  . . . . . . . . . . . . . . .  20
  110.  
  111.           V. COMPILATION AND LIMITATIONS  . . . . . . . . . . . . . . .  24
  112.  
  113.           VI. REVISION HISTORY  . . . . . . . . . . . . . . . . . . . .  25
  114.                A.  Version 1.0  . . . . . . . . . . . . . . . . . . . .  25
  115.                B.  Version 1.1  . . . . . . . . . . . . . . . . . . . .  25
  116.                C.  Version 1.2  . . . . . . . . . . . . . . . . . . . .  25
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.           Mat-P 4
  125.  
  126.  
  127.           I. INTRODUCTION
  128.  
  129.  
  130.  
  131.           PMAT is Turbo Pascal (TP) source code for recursive matrix
  132.           algebra.  The program is based on another program I wrote in C to
  133.           do the same thing. Both use a stack of matrices to keep track of
  134.           intermediate heap allocations. Once I figured it out in C it was
  135.           pretty easy to step back and do it in Pascal.  The object
  136.           oriented extensions in TP also helped smooth the process. This
  137.           allowed a convenient scheme to allow matrices to be larger than
  138.           64K.
  139.  
  140.           Of course you can't overload operators in TP, so the recursion is
  141.           messy. However, you can keep track of intermediate allocations on
  142.           the heap using PMAT. 
  143.  
  144.                new( a, makematrix( 1, 1 ) );
  145.                x = matequals(x, add( a,add(b,c))); 
  146.  
  147.           This code segment has to keep track of matrix allocations on the
  148.           heap, and then delete the temporary matrices. In this example,
  149.           the sum of B and C is a temporary matrix which would be lost
  150.           without some sort of global memory allocation tracking such as a
  151.           stack.  Its memory should be deleted after the equals function is
  152.           called. The stack helps avoid the assignment of temporaries in
  153.           recursive calls.
  154.  
  155.           On a more personal note, I wrote this program for fun. I started
  156.           on this problem in TP 3.0 when that was the best compiler on the
  157.           market (1984). I never really got a satisfactory answer, so I set
  158.           it down. Then I picked it up in Turbo C, and didn't get a
  159.           satisfactory answer. Then I picked it up in C++, and got a good
  160.           answer in about 1990 (see YAMP on the BPROGB of Compuserve). Then
  161.           I wrote it in C with good results, then TP 6.0 just for old times
  162.           sake. I had forgotten how fast TP compiles. It's a real code
  163.           blaster. Object oriented programming in TP 6 also helped. I guess
  164.           I learned some computer science along the way too. 
  165.  
  166.  
  167.           II. FINANCIAL CONDITIONS OF USE
  168.  
  169.  
  170.           If you like this program, send me $5.00 US (or buy a deserving
  171.           beggar lunch. In either case, find a way to repay my charity.)
  172.           You may distribute the package unchanged. I only plan to
  173.           distribute it electronically. I retain the copyright as proof of
  174.           authorship.
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.           Mat-P 5
  183.  
  184.           III. BASIC ALGORITHMS
  185.  
  186.  
  187.                A. Structures and Allocation
  188.  
  189.  
  190.           PMAT has two important objects: vmatrix and mstack. The vmatrix
  191.           object is declared in the interface 
  192.  
  193.                vmatrixptr = ^vmatrix;
  194.                vmatrix = Object
  195.                   r, c : integer;
  196.                   Function m( i, j: integer ): double;
  197.                   Function mm( i, j: integer ) : fp;
  198.                   constructor MakeMatrix( vr, vc: integer );
  199.                   Destructor KillVmatrix;
  200.                   Procedure Garbage;
  201.                   Procedure Show( strng: String );
  202.                   Procedure infomatrix( strng: String );
  203.  
  204.                   private
  205.                      v,vcheck: ^app;
  206.                      nelems : longint;
  207.                      onstack : boolean;
  208.                      Procedure purgevectors;
  209.                      Procedure allocvectors( rr, cc: integer );
  210.                End;
  211.  
  212.  
  213.           The vmatrix contains integers for the dimensions of the matrices,
  214.           an array of pointers to vectors of doubles, the number of
  215.           elements, and a check address. Matrix allocation is based on
  216.           Numerical Recipes in C . An array of addresses of vectors of
  217.           doubles is allocated first. Then, an array is allocated and its
  218.           first address is stored in the address vector. This method allows
  219.           matrices larger than 64K and scatters the rows of the matrix
  220.           throughout the heap. A row is restricted to 8190 doubles to keep
  221.           it under 64K. 
  222.  
  223.           Object oriented programming helped hide the ugly notation
  224.           required for storing and retrieving elements from a vmatrix. You
  225.           use the member function mm(i,j) to store elements in the matrix,
  226.           and m(i,j) to retrieve elements. An example is
  227.  
  228.                x^.mm(i,j)^ := y^.m(i,j);
  229.  
  230.           where x and y are vmatrix pointers. Note the extra ^ in
  231.           x^.mm(i,j)^. This returns the address in the heap for storing an
  232.           element. Using x^.mm(i,j) won't work. Think of element assignment
  233.           as saying "put y^.m(i,j) in the address pointed to by
  234.           x^.mm(i,j)". Using m(i,j) returns a double via
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.           Mat-P 6
  243.  
  244.                m := v^[i]^[j];
  245.  
  246.  
  247.           and using mm(i,j) returns an address via
  248.  
  249.               mm := @v^[i]^[j];
  250.  
  251.           Using member functions protects you from having to type these
  252.           unintuitive indexing operations. I also allows easy access to
  253.           matrices larger than 64K. They also do range checking on the
  254.           indexes.
  255.  
  256.           The check pointer contains the value of v upon allocating the
  257.           matrix. Then it is set to zero upon deallocation of v. The check
  258.           value is used in the member function Garbage(). If v does not
  259.           equal vcheck, then the matrix has been deallocated, or memory may
  260.           have been corrupted. The program halts if you try to use a
  261.           garbage matrix (better safe than sorry!). 
  262.  
  263.           The boolean variable, onstack, indicates that the matrix is on
  264.           the stack (onstack = true) or not (onstack = false). This
  265.           controls how matrices are copied. Its initial value is false. It
  266.           is set to true by push(), and false by pop(). See CopySD().
  267.  
  268.           PMAT expects you to use pointers to matrices, so allocation looks
  269.           like this
  270.  
  271.           procedure junk;
  272.           var x,y,z : vmatrixptr;
  273.           begin
  274.                new( x, makematrix( 1, 1 ) );
  275.                new( y, makematrix( 1, 1 ) );
  276.                new( z, makematrix( 1, 1 ) );
  277.                         .
  278.                         .
  279.                         .
  280.                { put code that uses x,y,z }
  281.                         .
  282.                         .
  283.                         .
  284.               dispose( x, killvmatrix );
  285.               dispose( y, killvmatrix );
  286.               dispose( z, killvmatrix );
  287.           end;
  288.                   
  289.           Call the constructor for each matrix, then make sure to dispose
  290.           of the storage at the end of the procedure. Your program will
  291.           develop memory leaks if you do not dispose of the vmatrix
  292.           pointers. PMAT is not consistent with the MARK-RELEASE method of
  293.           allocating memory.
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.           Mat-P 7
  302.  
  303.           The mstack type is 
  304.  
  305.                mstackptr = ^mstack;
  306.                mstack = Object
  307.                   constructor InitMatrixStack;
  308.                   Destructor KillMatrixStack;
  309.                   Procedure inclevel;
  310.                   Procedure declevel;
  311.                   Function ReturnMat: vmatrixptr;
  312.                   Function DecReturn: vmatrixptr;
  313.                   Procedure push( Var a: vmatrixptr );
  314.                   Procedure nrerror( strng: String );
  315.                   Procedure DumpStack;
  316.  
  317.                   private
  318.                     nummats, level : integer;
  319.                     next : mstackptr;
  320.                     mv : vmatrixptr;
  321.                     Procedure cleanstack( a: vmatrixptr );
  322.                     Function pop: vmatrixptr;
  323.                End;
  324.  
  325.  
  326.  
  327.           The mstack structure is a typical single linked list sort of
  328.           thing. The nummats field contains the number of matrices on the
  329.           stack. The level field contains the subroutine nesting level
  330.           which keeps track of which temporary matrices to be disposed. As
  331.           you enter and leave functions that use matrix assignment, you
  332.           increment and decrement the function nesting level. The
  333.           mstackptr, next, is a pointer to the next mstack object. The
  334.           vmatrixptr mv is the address of a vmatrix object referenced by
  335.           the stack object. 
  336.  
  337.  
  338.                B. The global stack: dispatch
  339.  
  340.           Mstack objects are stored in the global stack linked list with a
  341.           base pointer called dispatch. Dispatch is automatically
  342.           initialized in the use statement. 
  343.  
  344.           Dereference items in dispatch using the ^. operator, such as
  345.           dispatch^.level. The stack also has a tail, so if you try to
  346.           deallocate it, the program stops. It has a value of nil in the
  347.           field called next.
  348.  
  349.                C. Recursion
  350.  
  351.           The recursive matrix functions push mstack pointers onto the
  352.           stack. The address of the matrix reference is stored in mv. You
  353.           create stack elements when you call the push function. mstack
  354.           elements are deallocated automatically by other functions, so you
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.           Mat-P 8
  363.  
  364.           don't have to do it.  Popping occurs during calls to matequals()
  365.           for matrix assignment. Temporary mstack pointers are freed during
  366.           matequals by the garbage collector function, CleanStack(). You do
  367.           not have to pop explicitly. 
  368.  
  369.           The only part of mstack that you have to pay attention to is the
  370.           function nesting level. Garbage collection occurs during
  371.           assignment. Any function that uses matrix assignment pushes
  372.           matrices onto dispatch. Stack elements are deleted during garbage
  373.           collection if their value of level is greater than or equal to
  374.           the value of level held in dispatch. This way, each function has
  375.           its own stack, but all stack elements are stored in the same
  376.           linked list.
  377.  
  378.           You control level with the member functions, Inclevel(),
  379.           Declevel(), and DecReturn(). Inclevel() and Declevel() increment
  380.           or decrement level. Declevel() checks that level has not become
  381.           negative. The program stops if it has. 
  382.  
  383.           DecReturn() is used for returning matrices from functions. It
  384.           decrements the nesting level, and returns the address of the
  385.           matrix, v, in dispatch^.next. An example of returning a matrix
  386.           pointer recursively is 
  387.  
  388.  
  389.           function f1: vmatrixptr;
  390.           var x: vmatrixptr;
  391.           begin
  392.              dispatch^.inclevel;
  393.              new( x, makematrix(1,1));
  394.              x := matequals(x, ident(5) );
  395.              dispatch^.push(x);
  396.              f1 := dispatch^.decreturn;
  397.           end;
  398.  
  399.           The stack works by manipulating pointers to vmatrix objects,
  400.           rather than copies. This is faster and uses less memory. The
  401.           matrix pointer is pushed onto the stack. Then the function level
  402.           is decremented, and the pointer x is returned as
  403.           dispatch^.next^.mv. There is no need to dispose x, since it is
  404.           just a pointer stored in a global stack. The stack functions will
  405.           dispose it when it is appropriate.
  406.  
  407.                D. Matrix Assignment
  408.  
  409.           Matrix assignment is accomplished using the function matequals,
  410.           having prototype
  411.  
  412.           Function matequals(Var lop: vmatrixptr; rop: vmatrixptr) :        
  413.                  vmatrixptr;
  414.  
  415.           The statement from the example above uses assignment
  416.  
  417.  
  418.  
  419.  
  420.  
  421.  
  422.  
  423.           Mat-P 9
  424.  
  425.              x := matequals( x, ident(5) );
  426.  
  427.           The matrix being assigned must be used in two places. The first
  428.           place is in the function call where the contents of the matrix
  429.           objects are manipulated. The second is on the left of the equals
  430.           sign where the current function is told where the new address of
  431.           x is to be found.
  432.  
  433.           Matequals first checks that the two inputs are not garbage. Then
  434.           it checks if the two inputs point to the same 2 dimensional
  435.           array. If they do, then the matrix a gets a new 2 dimensional
  436.           array. The contents of rop are copied into lop. Then the
  437.           intermediate stack matrices are deleted. 
  438.  
  439.  
  440.                E. Parameter Passing
  441.  
  442.  
  443.           Parameter passing of matrices is the same as in ordinary Pascal.
  444.           If you want to change the contents of a matrix that was passed as
  445.           a parameter, then declare it a var parameter in the procedure.
  446.           Make sure that the matrix is correctly initialized before the
  447.           call. Then use matrix assignment to make the changes in the
  448.           matrix. Here is an example.
  449.  
  450.           procedure f1( var a: vmatrixptr );
  451.           begin
  452.              dispatch^.inclevel;
  453.              a := matequals(a,ident(3));
  454.              dispatch^.declevel;
  455.           end;
  456.           procedure f2( void );
  457.           var x:vmatrixptr;
  458.           begin
  459.                dispatch^.inclevel;
  460.                new(x,makematrix(1,1));
  461.                x^.show('before pass');
  462.                f1(x);
  463.                x^.show('after pass');
  464.                dispose(x,killvmatrix);
  465.                dispatch^.declevel;
  466.           end;
  467.  
  468.  
  469.           The call to  f1 in f2() passes x as a var vmatrix pointer. The
  470.           function call changes the contents of x from a 1x1 matrix to the
  471.           3x3 identity matrix.
  472.  
  473.           This example clarifies why matequals() needs to use the formal
  474.           parameter name on the left of the equals sign. You have to tell
  475.           the program where you put the new copy of the vmatrix.
  476.  
  477.  
  478.  
  479.  
  480.  
  481.  
  482.  
  483.           Mat-P 10
  484.  
  485.  
  486.  
  487.  
  488.           IV. FUNCTIONS
  489.  
  490.  
  491.           There are several kinds of functions in PMAT. They fall in
  492.           several categories:
  493.  
  494.                0. error handling
  495.                1. array allocation or deallocation
  496.                2. stack control
  497.                3. matrix allocation, deallocation and copy
  498.                4. display
  499.                5. IO
  500.                6. binary matrix functions
  501.                7. unary matrix function
  502.                8. patterned matrices
  503.                9. mathematical functions
  504.  
  505.           The interface should provide a quick reference to the names and
  506.           spellings. The following discussion explains the header.
  507.  
  508.                A. Error Handling
  509.  
  510.  
  511.           Procedure nrerror( strng: String );
  512.  
  513.           This is the error handler from Numerical Recipes in C. It is
  514.           called whenever a fatal error occurs. It prints the error text
  515.           and exits with a value 1. It is a member function of mstack
  516.           objects. Call it as dispatch^.nrerror('something''s happening
  517.           here');
  518.  
  519.  
  520.           Procedure Garbage;
  521.  
  522.           This function checks if the matrix a has been deleted or
  523.           corrupted. It calls nrerror if it has. This is a vmatrix member
  524.           function. Call it as x^.Garbage;
  525.  
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.           Mat-P 11
  533.  
  534.                B. Array Allocation or Deallocation
  535.  
  536.           The declarations form the structure for matrices.
  537.  
  538.                ap = Array[1..1] Of double;
  539.                apptr = ^ap;
  540.                app = Array[1..1] Of apptr;
  541.  
  542.           The type ap is an array of doubles. Note that the range is from 1
  543.           to 1, and the array is subscriptable and variable length. Range
  544.           checking is turned off in the matrix allocation and indexing
  545.           functions so that these arrays act like they do in C. Each row of
  546.           the matrix is allocated separately by new(apptr). Each new apptr
  547.           is stored in an subscripatble, variable length array of pointers
  548.           to arrays of doubles.
  549.  
  550.  
  551.           Procedure allocvectors( rr, cc: integer )
  552.  
  553.           Arrays are allocated using the Numerical Recipes in C method for
  554.           dmatrix arrays. Matrices in PMat are indexed from 1 to r, and 1
  555.           to c. 
  556.  
  557.  
  558.           procedure purgevectors.
  559.  
  560.           Arrays are freed using the Numerical Recipes in C method for
  561.           dmatrix arrays. 
  562.  
  563.           Neither of these functions need to be called directly since they
  564.           are called by the vmatrix construction routines. They are private
  565.           to the vmatrix class, so they cannot be used outside of the
  566.           pmat.pas unit.
  567.  
  568.  
  569.                C. Stack Control
  570.  
  571.           dispatch: mstackptr; (* stack top: global *)
  572.  
  573.           This declaration in the interface makes dispatch available to all
  574.           units that use pmat. It is allocated automatically from the use
  575.           statement.
  576.  
  577.  
  578.           constructor InitMatrixStack; (* set up stack top and tail *)
  579.  
  580.           This function allocates dispatch and the stack tail. It is called
  581.           by the pmat initialization routine.
  582.  
  583.           Procedure push( Var a: vmatrixptr ); { push a matrix onto stack }
  584.  
  585.           pushes a matrix onto the stack. It should be called before a f1
  586.  
  587.  
  588.  
  589.  
  590.  
  591.  
  592.  
  593.           Mat-P 12
  594.  
  595.           := dispatch^.ReturnMat; or f1 := dispatch^.DecReturn; call. The
  596.           new matrix is stored in dispatch^.next^.mv. push() also sets
  597.           a^.onstack to true. This is a member function of mstack.
  598.  
  599.  
  600.           Function pop: vmatrixptr; (* free dispatch->next, return v*)
  601.  
  602.           pop is a private function of the matrix stack. You should not
  603.           call it. It is called repetitively by CleanStack to delete
  604.           temporary matrices. It deletes the matrix structure, and returns
  605.           the matrix pointer mv. pop() also sets mv^.onstack to false.
  606.  
  607.  
  608.           vmatrix *ReturnMat( void );    /* return stack top matrix */
  609.  
  610.  
  611.           ReturnMat() returns the value dispatch^.next^.v in functions that
  612.           have not incremented the function nesting level, i.e. required
  613.           matrix assignment. It does not modify the subroutine nesting
  614.           level. All of the binary matrix functions push a vmatrix pointer
  615.           onto the stack, and then return by the statement "f1 :=
  616.           dispatch^.ReturnMat;". It is a public member function of mstack.
  617.  
  618.  
  619.           Function DecReturn: vmatrixptr; (* return stack to 
  620.                                             matrix,decrement level*)
  621.  
  622.           DecReturn returns the value dispatch^.next^.v in functions that
  623.           have incremented the function nesting level, i.e. required matrix
  624.           assignment. It decrements the subroutine nesting level. Functions
  625.           that use matrix assignment, such as inv(), push matrix pointers
  626.           onto the stack, and then return by the statement 
  627.           "f1 := dispatch^.DecReturn;". This is a public member function of
  628.           mstack.
  629.  
  630.  
  631.           Procedure inclevel; (* increment function nesting level *)
  632.  
  633.           Inclevel() increments the function nesting level. See the
  634.           discussion of the stack and recursion. This a public member
  635.           function of mstack, and is called as dispatch^.inclevel.
  636.  
  637.  
  638.           Procedure declevel; (* decrement function nesting level *)
  639.  
  640.           Declevel() decrements the function nesting level. It also checks
  641.           that the level has become negative. If so, it calls nrerror().
  642.           This indicates that level has been decremented more often than it
  643.           has been incremented. Check the Inclevel()-Declevel() pairs, or
  644.           the Inclevel()-DecReturn() pairs. See the discussion of the stack
  645.           and recursion. This a public member function of mstack, and is
  646.           called as dispatch^.declevel. Use this function when you use
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.           Mat-P 13
  655.  
  656.           matrix assignment in a procedure, but do not want to return a
  657.           matrix.
  658.  
  659.  
  660.           Procedure cleanstack( a: vmatrixptr );
  661.                   (* pop stack elements if level >= dispatch^.level *)
  662.  
  663.           CleanStack() is a private function of the stack. It should not be
  664.           called by the user. The argument is a matrix that is not to be
  665.           freed. Thus the call "CleanStack( x )" indicates that all
  666.           matrices with level at or above  dispatch^.level should be freed,
  667.           except for matrices that have the same address as x. It calls pop
  668.           while (m^.level >= dispatch^.level), and (dispatch^.next^.next !=
  669.           NIL). It frees all matrices not equal to x.
  670.  
  671.  
  672.           Function matequals( Var lop: vmatrixptr; rop: vmatrixptr ) :
  673.           vmatrixptr; (* copy rop into lop *)
  674.  
  675.           The matrix being assigned must be used in two places. The first
  676.           place is in the function call where the contents of the matrix
  677.           structure are manipulated. The second is on the left of the
  678.           equals sign where the current function is told where the new
  679.           address of x is to be found.
  680.  
  681.           matequals() first checks that the two inputs are not garbage. The
  682.           contents of rop are copied into lop by CopySD(). Then the
  683.           intermediate stack matrices are deleted by CleanStack().
  684.  
  685.  
  686.                D. Matrix Allocation, Deallocation and Copy
  687.  
  688.           constructor MakeMatrix( vr, vc: integer );
  689.                (* allocate a matrix *)
  690.  
  691.           MakeMatrix() constructs a matrix with vr rows and vc columns.
  692.           This should be called to properly construct a matrix before using
  693.           it in the matrix functions. This is a public member function of
  694.           vmatrix, and should be called as new(x, makematrix(1,1));
  695.  
  696.  
  697.           Destructor KillVmatrix; (* deallocate a matrix *)
  698.  
  699.           This frees the matrix storage in m^.v, and then dispose m. It
  700.           calls nrerror if m is corrupted. It is a public member function
  701.           of vmatrix and should be called as dispose(m,killvmatrix);
  702.  
  703.  
  704.           Procedure CopySD( Var source, dest: vmatrixptr );  
  705.                                     (* copy a matrix from source to dest *)
  706.  
  707.           This function should be considered private to the stack function,
  708.  
  709.  
  710.  
  711.  
  712.  
  713.  
  714.  
  715.           Mat-P 14
  716.  
  717.           matequals(). It is also hidden to the user in the implementation
  718.           of pmat. 
  719.  
  720.           CopySD() replaces the contents in the destination matrix by a
  721.           copy of the contents in the source matrix. If source and dest are
  722.           the same, then CopySD() returns immediately since you are trying
  723.           to copy a matrix onto itself. 
  724.  
  725.  
  726.           CopySD() recognizes when matrices are being copied from the
  727.           stack. Matrices being copied from the stack are about to be
  728.           deleted by Cleanstack(), so their matrix pointer is popped into
  729.           the destination matrix pointer. The destination matrix storage is
  730.           released first. The indices are reset. Next, the stack matrix
  731.           pointer is popped into the destination matrix pointer. Then the
  732.           function returns. 
  733.  
  734.           If the matrices point to the same dmatrix, and the source matrix
  735.           is not on the stack, then a new dmatrix array is allocated for
  736.           dest. If they have a different number of rows or columns, the
  737.           destination 2D array is reallocated to have the same number of
  738.           rows and columns. Then the dmatrix array contents of the source
  739.           are copied into the destination.
  740.  
  741.  
  742.  
  743.                E. Display Functions
  744.  
  745.  
  746.           Procedure DumpStack;
  747.  
  748.           This dumps the stack. It is the only function that may be called
  749.           between push and the function return. It is for debugging
  750.           purposes. It is a public member function of mstack and should be
  751.           called as dispatch^.dumpstack;
  752.  
  753.  
  754.           Procedure infomatrix( strng: String ); (* show dimensions *)
  755.  
  756.  
  757.           infomatrix() displays information about the matrix. The strng is
  758.           a string describing the matrix. The string, strng, is displayed,
  759.           then the number of rows, columns, m, and mcheck.  Use
  760.           infomatrix() when the matrix is large, or when you are having
  761.           problems with corrupted or deleted matrices. This is a public
  762.           function of vmatrix and should be called as x^.Infomat('something
  763.           is happening here');
  764.  
  765.  
  766.  
  767.  
  768.  
  769.  
  770.  
  771.           Mat-P 15
  772.  
  773.           Procedure Show( strng: String );(* display matrix *)
  774.  
  775.           show() displays a matrix. The string, strng is also displayed
  776.           before the matrix elements. You can control the width and decimal
  777.           places by calling setwid() and setdec() before calling show().
  778.           This is public function of vmatrix and a  typical call is
  779.           "x^.show("x");"
  780.  
  781.  
  782.  
  783.           Procedure setwid( wid: integer );      (* set display width *)
  784.           Procedure setdec( decimals: integer ); (* set display decimals *)
  785.           Function getwid: integer;              (* get display width *)
  786.           Function getdec: integer;              (* get display decimals *)
  787.  
  788.  
  789.           setwid() and setdec() store hidden global integers for the
  790.           display width and decimals. show() and Writea() call getwid() and
  791.           getdec() to use these variables.  
  792.  
  793.  
  794.  
  795.                F. Matrix IO
  796.  
  797.  
  798.           External matrices are stored in an ASCII character format. The
  799.           first row is a title string that is at most 80 characters
  800.           including the final carriage return, '\n'. The second row
  801.           contains two integers separated by white space. The first integer
  802.           is the number of rows, r, and the second is the number of
  803.           columns, c. The next rows are the rows of the matrix. Matrix may
  804.           span several text rows, but there must be r*c elements. 
  805.  
  806.           Function reada( fid: String ): vmatrixptr; 
  807.                                  (* read ascii matrix *)
  808.  
  809.  
  810.           Reada() reads a matrix stored in the ASCII file pointed to by
  811.           fid. Reada() terminates if the title string is longer than 80
  812.           total characters, including the terminal carriage return, '\n'.
  813.           Reada() should be called in a matrix assignment since it returns
  814.           a matrix off of the stack. As an example,
  815.  
  816.                x := matequals( x, Reada('xmatrix.dat');
  817.  
  818.  
  819.           Procedure writea( fid: String; a: vmatrixptr; titlestr: String );
  820.                                 (* write ascii matrix *)
  821.  
  822.           Writea() stores a vmatrix, a, in file, fid, using the PMat ASCII
  823.           file format. Data is written to fid using the current print
  824.           display values found in setdec() and setwid(). The title string
  825.  
  826.  
  827.  
  828.  
  829.  
  830.  
  831.  
  832.           Mat-P 16
  833.  
  834.           is truncated to 80 characters (including '\n') if it is longer
  835.           than 80 characters.
  836.  
  837.  
  838.  
  839.                G. Binary Matrix Functions
  840.  
  841.  
  842.           The binary matrix functions are recursive in that they push
  843.           matrices onto the stack, and do not manipulate the function
  844.           nesting level. They all push a vmatrix pointer onto the stack,
  845.           and return a vmatrix pointer using a call to ReturnMat(). The
  846.           incoming matrices are checked by calling Garbage() before doing
  847.           any calculations. A typical use of these functions is 
  848.  
  849.  
  850.                (*  d= a+(b-c) ; *)
  851.                d = equals( d, add(a,sub(b,c)));
  852.  
  853.           The call to equals deletes the temporary difference of c from b.
  854.           Scalars may also be used in binary operations. Each of the binary
  855.           matrix functions have "sc" appended to the left(right) if a
  856.           scalar is to be added to a matrix on the left(right).
  857.  
  858.  
  859.           function add( a, b: vmatrixptr ): vmatrixptr;  (* addition a+b *)
  860.           function scadd( a: double; b: vmatrixptr): vmatrixptr;
  861.           function addsc( b: vmatrixptr; a: double); vmatrixptr;
  862.  
  863.           Matrix addition, conditions : a^.r == b^.r and a^.c == b^.c
  864.           The scalar additions add a double to a matrix.
  865.  
  866.  
  867.           Function sub( A, B: vmatrixptr ):vmatrixptr; (* subtraction a-b*)
  868.           Function scsub( a: double; b: vmatrixptr): vmatrixptr;
  869.           Function subsc( b: vmatrixptr; a: double); vmatrixptr;
  870.  
  871.           Matrix subtraction, conditions : a^.r = b^.r and a^.c = b^.c
  872.           The scalar subtractions perform the subraction in the indicated
  873.           order: scsub(i,j) = A - b(i,j), subsc(i,j)= b(i,j)-A.
  874.  
  875.  
  876.           Function Mult( A, B: vmatrixptr ):vmatrixptr;(*matrix mult a*b*)
  877.  
  878.           Caley multiplication, inner products are formed using extended
  879.           doubles, then truncated back to doubles when stored in a matrix.  
  880.                conditions : a^.c = b^.r.
  881.  
  882.  
  883.  
  884.  
  885.  
  886.  
  887.  
  888.           Mat-P 17
  889.  
  890.           Function emult( a, b: vmatrixptr ):vmatrixptr;
  891.                                     (* elementwise mult a#b *)
  892.           function scmult( a: double; b: vmatrixptr): vmatrixptr;
  893.           function multsc( b: vmatrixptr; a: double); vmatrixptr;
  894.  
  895.  
  896.           Elementwise multiplication, 
  897.               conditions : a^.r = b^.r and a^.c = b^.c
  898.           The scalar multiplications multiply the elements of b by a.
  899.  
  900.  
  901.  
  902.           Function divis(a,b:vmatrixptr): vmatrixptr;
  903.           function scdivis( a: double; b: vmatrixptr): vmatrixptr;
  904.           function divissc( b: vmatrixptr; a: double); vmatrixptr;
  905.  
  906.  
  907.           Elementwise division,
  908.                 conditions : a^.r = b^.r and a^.c = b^.c and for all i,j    
  909.              b^.m(i,j) <> 0
  910.           The scalar divisions perform division in the indicated order:
  911.           scdivis(i,j) = A/b(i,j), divissc(i,j)= b(i,j)/A.
  912.  
  913.  
  914.  
  915.                H. Unary Matrix Functions
  916.  
  917.  
  918.           The unary matrix functions, neg(), tran(), and inv(), are
  919.           recursive in that they push matrices onto the stack, and do not
  920.           manipulate the function nesting level. neg(), and tran() push a
  921.           vmatrix pointer onto the stack, and return a vmatrix pointer
  922.           using a call to ReturnMat(). inv() uses matrix assignment so  it
  923.           increments the nesting level, pushes the return matrix, and
  924.           returns by a call to DecReturn(). The incoming matrices are
  925.           checked by calling Garbage() before doing any calculations. A
  926.           typical use of these functions is 
  927.  
  928.  
  929.  
  930.  
  931.  
  932.  
  933.  
  934.           Mat-P 18
  935.  
  936.           function regression: vmatrixptr;
  937.           var x,y,xpx,xpy,beta : vmatrixptr;
  938.           begin
  939.                (* beta = inv(x'x)x'y *)
  940.                dispatch^.Inclevel;
  941.                new(x, makematrix(1,1));
  942.                new(y, makematrix(1,1));
  943.                new(xpx, makematrix(1,1));
  944.                new(xpy, makematrix(1,1));
  945.                new(beta, makematrix(1,1));
  946.                x := matequals( x, Reada( "x.dat") );
  947.                y := matequals( y, Reada( "y.dat") );
  948.                xpx := matequals( xpx, mult( tran(x), x ));
  949.                xpy := matequals( xpy, mult( tran(x), y ));
  950.                beta := matequals( beta, mult( inv(xpx), xpy));
  951.                dispose( x, killvmatrix);
  952.                dispose( y, killvmatrix);
  953.                dispose( xpx, killvmatrix);
  954.                dispose( xpy, killvmatrix);
  955.                dispatch^.push( beta );
  956.                regression := dispatch^.DecReturn;
  957.           end;
  958.  
  959.           function sweepreg: vmatrixptr;
  960.           var xy, xypxy, beta : vmatrixptr;
  961.           begin
  962.                (* beta using sweep *)
  963.                dispatch^.Inclevel;
  964.                new(xy, makematrix(1,1));
  965.                new(xypxy, makematrix(1,1));
  966.                new(beta, makematrix(1,1));
  967.                xy := matequals( xy, Reada( "xy.dat") );
  968.                xypxy := matequals( xypxy, mult( tran(xy), xy ));
  969.                xypxy := equals( xypxy, sweep( xypxy, 1, xy^.c - 1) );
  970.                beta := matequals( beta, 
  971.                          submat( xypxy, 1, xy^.c -1, xy^.c, xy^.c) );
  972.                dispose( xy, killvmatrix);
  973.                dispose( xypxy, killvmatrix);
  974.                dispatch^.push( beta );
  975.                sweepreg := dispatch^.DecReturn;
  976.           end;
  977.  
  978.  
  979.           Function neg( A: vmatrixptr ): vmatrixptr;(* negation *)
  980.  
  981.           Changes the sign of all elements.
  982.  
  983.  
  984.           Function tran( a: vmatrixptr ): vmatrixptr;(* transpose *)
  985.  
  986.           Matrix transpose: c^.m(i,j) = a^.m(j,i)
  987.  
  988.  
  989.  
  990.  
  991.  
  992.  
  993.  
  994.           Mat-P 19
  995.  
  996.           Function sweep( A: vmatrixptr; k1, k2: integer ) : vmatrixptr; 
  997.  
  998.           Sweep cols k1...k2 along the diagonal and in place in a. See the
  999.           example for how to use sweep for regression. Input matrix must be
  1000.           square. Row and columns having pivot elements less than 10E-8 are
  1001.           set to zero. This indicates a colinearity with at least one
  1002.           column that has already been swept out.
  1003.  
  1004.  
  1005.           Function inv( Amat: vmatrixptr ): vmatrixptr;
  1006.                                  (* inversion by sweep *)
  1007.  
  1008.           Calls sweep for inversion: x = matequals( x, sweep(x, 1, x^.c ));
  1009.           This is a Gaussian elimination inverter without column pivoting.
  1010.           It fails to accurately invert Hilbert matrices of dimension 8 or
  1011.           more, which is reasonable for inversion by Gaussian elimination.
  1012.  
  1013.  
  1014.  
  1015.  
  1016.                I. Patterned Matrices
  1017.  
  1018.           The patterned matrix functions are recursive. They push matrices
  1019.           onto the stack and return by calling ReturnMat. They should be
  1020.           used in conjunction with matrix assignment.
  1021.  
  1022.  
  1023.  
  1024.           Function submat( a: vmatrixptr; lr, r, lc, c: integer ):          
  1025.                     vmatrixptr;    (*submatrix*)
  1026.  
  1027.           Extract a submatrix of a, using rows lr to r, and columns lc to
  1028.           c. All integer arguments must be in the range of the dimension of
  1029.           a.
  1030.  
  1031.           Function ident( n: integer ): vmatrixptr;   (*identity matrix*)
  1032.  
  1033.           Construct an n dimensional Identity matrix
  1034.  
  1035.           Function fill( rr, cc: integer; d: double ):vmatrixptr;
  1036.                                    (* matrix of constants d *)
  1037.  
  1038.           Construct a rr x cc matrix of constants, d. 
  1039.  
  1040.           Function cv( a, b: vmatrixptr ): vmatrixptr;
  1041.                                   (* vertical concatenation *)
  1042.  
  1043.           Vertically concatenate b to a. a is on top, b is on bottom, and
  1044.           they must have the same number of columns.
  1045.  
  1046.  
  1047.  
  1048.  
  1049.  
  1050.  
  1051.  
  1052.           Mat-P 20
  1053.  
  1054.           Function ch( a, b: vmatrixptr ): vmatrixptr;
  1055.                   (* horizontal concatenation *)
  1056.  
  1057.           Horizontally concatenate b to a. a is on the left, b is on the
  1058.           right, and they must have the same number of rows.
  1059.  
  1060.  
  1061.           vmatrix *vecdiag( vmatrix *a );  
  1062.                                        (* place vector on diagonal *)
  1063.  
  1064.           Place elements of a rx1 or 1xc matrix on the diagonal of a square
  1065.           matrix.  
  1066.  
  1067.  
  1068.                J. Mathematical Functions
  1069.  
  1070.  
  1071.           The mathematical function module for YAMP was translated for
  1072.           PMAT. These are some of the many linear algebra functions that
  1073.           are used.
  1074.  
  1075.  
  1076.           function MSort(a :vmatrixptr; col, order: integer): vmatrixptr;
  1077.  
  1078.           Sort the rows of a matrix by a column if order is not equal to
  1079.           zero. If order is zero, then sort the columns of a matrix by a
  1080.           row.
  1081.  
  1082.  
  1083.           function Mexp(ROp: vmatrixptr): vmatrixptr;
  1084.           function Mabs(ROp: vmatrixptr): vmatrixptr;
  1085.           function Mlog(ROp :vmatrixptr): vmatrixptr;
  1086.           function Msqrt(ROp: vmatrixptr): vmatrixptr;
  1087.  
  1088.           These functions operate on the elements of a matrix. They halt if
  1089.           an argument is out of range. The take exp(a^.m(i,j)),
  1090.           abs(a^.m(i,j)), ln( a^.m(i,j)), and sqrt(a^.m(i,j)). You might
  1091.           consider adding the trig functions too.
  1092.  
  1093.  
  1094.           function Trace(ROp: vmatrixptr): double;
  1095.  
  1096.           Takes the sum of the diagonal elements of a square matrix.
  1097.  
  1098.  
  1099.           function Helm (n: integer): vmatrixptr;
  1100.  
  1101.           Returns the Helmert matrix of dimension n.
  1102.  
  1103.  
  1104.           function Index( lower,  upper, step : integer): vmatrixptr;
  1105.  
  1106.  
  1107.  
  1108.  
  1109.  
  1110.  
  1111.  
  1112.           Mat-P 21
  1113.  
  1114.           Returns an index matrix with elements between lower and upper,
  1115.           and in increments of step. If lower is less than upper, then step
  1116.           must be positive. If lower is greater than upper, then step must
  1117.           be negative.
  1118.  
  1119.  
  1120.           function Kron(a,b:vmatrixptr): vmatrixptr;
  1121.  
  1122.           Returns the Kroniker product of a and b. The blocks of the
  1123.           Kroniker product are a^.m(i,j)*b. 
  1124.  
  1125.  
  1126.  
  1127.  
  1128.  
  1129.  
  1130.  
  1131.           Mat-P 22
  1132.  
  1133.           function Det(Datain : vmatrixptr): double;
  1134.  
  1135.           Returns the determinant of Datain, which must be a square matrix.
  1136.  
  1137.  
  1138.           function Cholesky(ROp: vmatrixptr): vmatrixptr;
  1139.  
  1140.           Returns the Cholesky decomposition of a square symmetric matrix:
  1141.           ROp = S'S, where S is an upper triangular matrix. Cholesky stops
  1142.           if ROp is singular. This routine does not use pivoting.
  1143.  
  1144.  
  1145.           procedure QR(var ROp, Q, R: vmatrixptr; makeq: boolean);
  1146.  
  1147.           This procedure produces the QR decomposition of an rxc matrix:
  1148.           ROp=QR, where Q is an rxc matrix of orthogonal columns, and R is
  1149.           an upper triangular cxc matrix. This routine stops if a zero is
  1150.           detected along the diagonal of R. The variable makeq determines
  1151.           if Q is produced. The procedure calculates Q = ROp*Inv(R). If the
  1152.           calculation of Q is not required, or inversion of R is
  1153.           prohibative, then set makeq = FALSE to avoid the inversion of R.
  1154.  
  1155.  
  1156.           function Svd(var A, U, S, V : vmatrixptr;
  1157.                        makeu, makev: boolean) : integer;
  1158.  
  1159.           This function returns an integer indicating that the singular
  1160.           value decomposition has failed. The singular value decomposition
  1161.           is calculated as A = UDiag(S)V' where U and V are orthogonal
  1162.           matrices and S is a column vector containing the singular values
  1163.           of A. The singular values of A are the eigenvalues of A'A. If you
  1164.           wish to calculate U or V, then set makeu = TRUE or makev = TRUE
  1165.           respectively. 
  1166.  
  1167.  
  1168.           function Ginv( ROp : vmatrixptr): vmatrixptr;
  1169.  
  1170.           This function returns the generalized inverse from the singular
  1171.           value decomposition of ROp=UDiag(S)V'. The generalized inverse of
  1172.           ROp is Ginv(ROp) = VDiag(S+)U', where S+ is a diagonal matrix of
  1173.           the reciprocals of S. If S has a element of zero, the
  1174.           corresponding element of S+ is also zero.
  1175.  
  1176.  
  1177.           function Fft(ROp : vmatrixptr; INZEE : boolean): vmatrixptr;
  1178.  
  1179.           This function returns the fast Fourier transform of an input
  1180.           matrix ROp. The length of ROp may be any value. ROp may have 1 or
  1181.           2 columns. If it has 1 column, the vector is assumed to be a real
  1182.           vector. If the matrix has 2 columns, the matrix is assumed to
  1183.           consist of complex numbers. The first column contains the real
  1184.           part, and the second column contains the imaginary part. The
  1185.  
  1186.  
  1187.  
  1188.  
  1189.  
  1190.  
  1191.  
  1192.           Mat-P 23
  1193.  
  1194.           forward transform is calculated if INZEE is TRUE, and the inverse
  1195.           transform is calculated if INZEE is FALSE.
  1196.  
  1197.  
  1198.           function Vec( ROp : vmatrixptr): vmatrixptr;
  1199.  
  1200.           This functions stacks the columns of a matrix into a single
  1201.           column vector. Thus if ROp is rxc, then Vec(ROp) has r*c rows and
  1202.           1 column. The c blocks of Vec(ROp) are columns of ROp.
  1203.  
  1204.  
  1205.           function Diag(ROp : vmatrixptr): vmatrixptr;
  1206.  
  1207.           This function has two purposes. If the input matrix is a column
  1208.           or row vector, then Diag places the elements along the diagonal
  1209.           elements of square matrix of zeros. If the input matrix is
  1210.           square, then all of the off-diagonal elements are set to zero.
  1211.  
  1212.  
  1213.           function Shape(ROp: vmatrixptr; nrows: integer): vmatrixptr;
  1214.  
  1215.           This functions reshapes a matrix to have nrows rows. If ROp is
  1216.           has r*c elements, then nrows must divide r*c without a remainder.
  1217.  
  1218.  
  1219.           type  margins = (ALL,ROWS,COLUMNS);
  1220.  
  1221.           This enumerated type controls the actions of the next 5
  1222.           functions. If you use ALL, then the functions operate over all
  1223.           elements of the input matrix. If you use ROWS, then the functions
  1224.           operate over the rows of the input. If you use COLUMNS, then the
  1225.           functions operate over the columns of the matrix.
  1226.  
  1227.  
  1228.           function Sum(   ROp : vmatrixptr; marg : margins ) : vmatrixptr;
  1229.  
  1230.           This functions returns sum of the elements in a matrix. If
  1231.           marg=ALL, then the returned matrix is 1x1, containing the sum of
  1232.           all elements. If marg=ROWS then the return matrix has the same
  1233.           number of columns as ROp, and 1 row. Each column contains the sum
  1234.           of the row elements. If marg=COLUMNS then the return matrix has
  1235.           the same number of rows as ROp, and 1 column. Each row cantains
  1236.           the sum of the column elements.
  1237.  
  1238.  
  1239.           function Sumsq( ROp : vmatrixptr; marg: margins): vmatrixptr;
  1240.  
  1241.           This function is similar to Sum, except that it returns the sum
  1242.           of squared elements.
  1243.  
  1244.  
  1245.  
  1246.  
  1247.  
  1248.  
  1249.  
  1250.           Mat-P 24
  1251.  
  1252.           function Cusum( ROp : vmatrixptr): vmatrixptr;
  1253.  
  1254.           This function returns the cumulative sum across rows of matrix.
  1255.  
  1256.  
  1257.           function Mmax( ROp: vmatrixptr; marg : margins): vmatrixptr;
  1258.           function Mmin( ROp: vmatrixptr; marg : margins): vmatrixptr;
  1259.  
  1260.           These functions find the max and min elements of a matrix, and
  1261.           the position of the elements. If marg=ALL, then the functions
  1262.           return a 3x1 matrix. The first element is the row index of the
  1263.           max, the second element is the column index of the element, and
  1264.           the third element is the max(or min). If marg=ROWS, then the
  1265.           returned matrix is a 3xc matrix where the first row is the row
  1266.           index of the max(min) element in a column, the second row is the
  1267.           column index of the max(min) element, and the third row are the
  1268.           max(min) for the column. Similarly, if marg=COLUMNS, then a rx3
  1269.           matrix is returned.
  1270.  
  1271.  
  1272.           Procedure Crow(var ROp: vmatrixptr; row : integer; c : double);
  1273.           Procedure Srow(var ROp : vmatrixptr; row1, row2 : integer);
  1274.           Procedure Lrow(var ROp : vmatrixptr; row1, row2 : integer; c :    
  1275.             double);
  1276.           Procedure Ccol(var ROp : vmatrixptr; col : integer; c : double);
  1277.           Procedure Scol(var ROp : vmatrixptr; col1, col2 : integer);
  1278.           Procedure Lcol(var ROp : vmatrixptr; col1, col2 : integer; c :    
  1279.             double);
  1280.  
  1281.  
  1282.           These functions perform elementary row and column operations on
  1283.           matrices. They change the input matrices. The first letter
  1284.           indicates the operation. The next 3 letters indicate if the
  1285.           operation is for rows or columns. For Crow, the row indexed by
  1286.           row is multiplied by c. For Srow, row1 and row2 are swapped. For
  1287.           Lrow, row1 is multiplied by c, and added to row2. Ccol, Scol, and
  1288.           Lcol perform similar operations on columns.
  1289.  
  1290.  
  1291.  
  1292.           V. COMPILATION AND LIMITATIONS
  1293.  
  1294.  
  1295.           Programs using PMAT must include pmat in the uses statement. Also
  1296.           put pmatop in the uses statement if you use code from PMATOP.PAS.
  1297.  
  1298.           Compile and link the program. See mattest2.pas or testop.pas for 
  1299.           example files using PMat or PMatop. Also see makefile for a
  1300.           Borland make file for using the command line compiler. 
  1301.  
  1302.  
  1303.  
  1304.  
  1305.  
  1306.  
  1307.  
  1308.           Mat-P 25
  1309.  
  1310.           PMat does have some limitations. It is limited by the available
  1311.           memory in the machine, so large matrices will exhaust the heap,
  1312.           and the program will stop. This is bothersome on a PC without a
  1313.           DOS extender. The BP7 protected mode for DOS programs allows up
  1314.           to 16 megs of memory, and matrices may be larger than 640K. Note
  1315.           that a 1000x1000 of double takes 8 megs, so PMat may not be
  1316.           suitable for really large matrices.
  1317.  
  1318.           Another limitation is its readability. Using function calls
  1319.           rather than overloaded algebraic operators muddles things.  There
  1320.           is no other obvious way to do this in TP though. One trick I use
  1321.           to help me with this is to count open-close parenthesis pairs.
  1322.           Some programming editors help this too by blink the other member
  1323.           of the pair. Another trick is to keep recursive expressions on a
  1324.           single line. This helps with storage also, since the stack
  1325.           storage is cleaned up after each call to equals. If you have
  1326.           memory overflow problems, try splitting the recursive expressions
  1327.           into several parts by paying attention to where the big matrices
  1328.           are created. 
  1329.  
  1330.  
  1331.  
  1332.           VI. REVISION HISTORY
  1333.  
  1334.  
  1335.  
  1336.                A.  Version 1.0
  1337.  
  1338.           This is the original version. It is a copy of my matrix program
  1339.           C-Mat. I may extend PMAT to have most of the capability of YAMP,
  1340.           my C++ program. This would involve a virtual memory manager, a
  1341.           graphics module, and larger set of mathematical functions. I
  1342.           don't know if it is worth the effort though.
  1343.  
  1344.                B.  Version 1.1
  1345.  
  1346.           This version adds BP 7.0 compatability for protected mode DOS
  1347.           applications. The version 7 DPMI extender eliminates the need of
  1348.           a virtual memory manager. You need a 286 or 386 to use this
  1349.           feature.
  1350.  
  1351.                C.  Version 1.2
  1352.  
  1353.           Added a new module for the math functions from YAMP. This
  1354.           includes matrix sorts, elementwise functions, trace, helmert
  1355.           matrix, index matrix, Kroniker products, determinants, Cholesky
  1356.           decomposition, QR decomposition, singular valued decomposition,
  1357.           generalized inverse, fast Fourier transform, vec, diagonal,
  1358.           shape, sums, sums of squares, cumulative sums, max, min, and
  1359.           elementary row-column operations. Added arithmetic operations
  1360.           with scalars: scadd, addsc, etc.
  1361.